from pymodbus.server.asynchronous import StartTcpServer
from pymodbus.server.asynchronous import StartUdpServer
from pymodbus.server.asynchronous import StartSerialServer

from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from pymodbus.transaction import (ModbusRtuFramer,
                                  ModbusAsciiFramer,
                                  ModbusBinaryFramer)
from dcs_message import DcsModbusRequest
from dcs_framer import DcsModbusSocketFramer
from dcs_factory import DcsFactory
from schedule_task import task_collecting_data

# --------------------------------------------------------------------------- #
# configure the service logging
# --------------------------------------------------------------------------- #
import logging

FORMAT = ('%(asctime)-15s %(threadName)-15s'
          ' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s')
logging.basicConfig(format=FORMAT)
_logger = logging.getLogger()
_logger.setLevel(logging.DEBUG)


def _is_main_thread():
    import threading

    if threading.current_thread() != threading.main_thread():
        _logger.debug("Running in spawned thread")
        return False

    _logger.debug("Running in Main thread")
    return True


def StartTcpServer(context, identity=None, address=None,
                   console=False, defer_reactor_run=False, custom_functions=[],
                   **kwargs):

    from twisted.internet import reactor

    address = address or ("", 50200)
    framer = kwargs.pop("framer", DcsModbusSocketFramer)
    factory = DcsFactory(context, framer, identity, **kwargs)
    for f in custom_functions:
        factory.decoder.register(f)

    reactor.suggestThreadPoolSize(10)

    _logger.info("Starting Modbus TCP Server on %s:%s" % address)
    reactor.listenTCP(address[1], factory, interface=address[0])

    #run_schedule(factory)
    reactor.callLater(5, task_collecting_data, factory)

    if not defer_reactor_run:
        reactor.run(installSignalHandlers=_is_main_thread())


def run_async_server():

    Reg_MacStatus = 4000
    Reg_SpindleStatus = 4100
    Reg_SpindleSpeed = 5000
    Reg_Config = 8000

    store = ModbusSlaveContext(
        di=ModbusSequentialDataBlock(Reg_MacStatus, [11] * 27),
        co=ModbusSequentialDataBlock(Reg_SpindleStatus, [22] * 525),
        hr=ModbusSequentialDataBlock(Reg_SpindleSpeed, [33] * 2500),
        ir=ModbusSequentialDataBlock(Reg_Config, [44] * 40))

    store.register(DcsModbusRequest.function_code, 'dcs',
                   ModbusSequentialDataBlock(0, [17] * 100))

    context = ModbusServerContext(slaves=store, single=True)

    # ----------------------------------------------------------------------- #
    # initialize the server information
    # ----------------------------------------------------------------------- #
    # If you don't set this or any fields, they are defaulted to empty strings.
    # ----------------------------------------------------------------------- #
    identity = ModbusDeviceIdentification()
    identity.VendorName = 'jadeyo'
    identity.ProductCode = 'PM'
    identity.VendorUrl = 'http://www.jadeo.com'
    identity.ProductName = 'dcs Server'
    identity.ModelName = 'dcs Server'
    identity.MajorMinorRevision = '1.0.0'

    # TCP Server
    StartTcpServer(context, identity=identity, address=("0.0.0.0", 50200),
                   custom_functions=[DcsModbusRequest])


if __name__ == "__main__":
    run_async_server()